#ifndef WORKQUEUE_H__
#define WORKQUEUE_H__

#include "cc_core.h"
#include "cc_list.h"

enum
{
  CC_WORK_STATE_PENDING = 0x0001,    /* Work item pending state */
  CC_WORK_STATE_SUBMITTING = 0x0002, /* Work item submitting state */
};

enum
{
  WORKQUEUE_PENDING,
  WORKQUEUE_RUNNING
};

/**
 * work type defitions
 */
enum
{
  CC_WORK_TYPE_DELAYED = 0x0001,
};

/* cc_workqueue implementation */
struct cc_workqueue
{
  cc_list work_list;
  cc_list delayed_list;
  struct cc_work* work_current; /* current work */
  cc_sem sem;
  cc_cond cond;
  cc_mutex mutex;
  int state;
  cc_tid work_thread;
};

struct cc_work
{
  cc_list_node list;

  void (*work_func)(struct cc_work* work, void* work_data);
  void* work_data;
  uint16_t flags;
  uint16_t type;

  cc_timer timer;
  struct cc_workqueue* workqueue;
};

/**
 * @brief dynamic create a workqueue
 *
 * @param name the workqueue name
 * @param stack_size the workqueue size
 * @param priority  thread priority
 *
 * @return cc_workqueue pointer
 */
struct cc_workqueue* cc_workqueue_create(const char* name, uint16_t stack_size, uint8_t priority);
/**
 * @brief static create a workqueue
 *
 * @param name the workqueue name
 * @param stack_size the workqueue size
 * @param priority  thread priority
 *
 * @return cc_workqueue pointer
 */
int cc_workqueue_init(struct cc_workqueue* queue, const char* name, uint16_t stack_size, uint8_t priority);
/**
 * @brief destroy a workqueue
 *
 * @param queue workqueue pointer
 * @return error_code
 */
int cc_workqueue_destroy(struct cc_workqueue* queue);
/**
 * @brief deinit a workqueue
 *
 * @param queue workqueue pointer
 * @return error_code
 */
int cc_workqueue_deinit(struct cc_workqueue* queue);
/**
 * @brief do a work
 *
 * @param queue workqueue pointer
 * @param work work pointer
 * @return error_code
 */
int cc_workqueue_dowork(struct cc_workqueue* queue, struct cc_work* work);
/**
 * @brief submit a work
 *
 * @param queue workqueue pointer
 * @param work work pointer
 * @param time delay_time
 * @return error_code
 */
int cc_workqueue_submit_work(struct cc_workqueue* queue, struct cc_work* work,
                             uint32_t time);
/**
 * @brief cancel a work
 *
 * @param queue workqueue pointer
 * @param work work pointer
 * @return error_code
 */
int cc_workqueue_cancel_work(struct cc_workqueue* queue, struct cc_work* work);
/**
 * @brief cancel a work sync
 *
 * @param queue workqueue pointer
 * @param work work pointer
 * @return error_code
 */
int cc_workqueue_cancel_work_sync(struct cc_workqueue* queue, struct cc_work* work);
/**
 * @brief cancel all work
 *
 * @param queue workqueue pointer
 * @return error_code
 */
int cc_workqueue_cancel_all_work(struct cc_workqueue* queue);
/**
 * @brief submit a critical work
 *
 * @param queue workqueue pointer
 * @param work work pointer
 * @return error_code
 */
int cc_workqueue_critical_work(struct cc_workqueue* queue, struct cc_work* work);

/**
 * @brief submit a work to sys_workqueue
 *
 * @param queue workqueue pointer
 * @param work work pointer
 * @return error_code
 */
int cc_work_submit(struct cc_work* work, uint32_t time);

/**
 * @brief  cancel a work in sys_workqueue
 * @return error_code
 */
int cc_work_cancel(struct cc_work* work);

/**
 * @brief  init a work
 * @param work work pointer
 * @param work_func work callback func
 * @param work_data data
 */
int cc_work_init(struct cc_work* work,
                 void (*work_func)(struct cc_work* work, void* work_data), void* work_data);

#endif
